<!--
Copyright 2013 The Polymer Authors. All rights reserved.
Use of this source code is governed by a BSD-style
license that can be found in the LICENSE file.
-->
<!--
/**
 * @module Polymer Elements
 */
/**
 * polymer-ajax can be used to perform XMLHttpRequests.
 *
 * Example:
 *
 *     <polymer-ajax auto url="http://gdata.youtube.com/feeds/api/videos/" 
 *         params='{"alt":"json", "q":"chrome"}'
 *         handleAs="json"
 *         on-polymer-response="handleResponse">
 *     </polymer-ajax>
 *
 * @class polymer-ajax
 */
/**
 * Fired when a response is received.
 * 
 * @event polymer-response
 */
/**
 * Fired when an error is received.
 * 
 * @event polymer-error
 */
/**
 * Fired whenever a response or an error is received.
 *
 * @event polymer-complete
 */
-->
<link rel="import" href="polymer-xhr.html">

<polymer-element name="polymer-ajax" attributes="url handleAs auto params response">
  <script>
    Polymer('polymer-ajax', {
      /**
       * The URL target of the request.
       * 
       * @attribute url
       * @type string
       * @default ''
       */
      url: '',
      /**
       * Specifies what data to store in the 'response' property, and
       * to deliver as 'event.response' in 'response' events.
       * 
       * One of:
       * 
       *    `text`: uses XHR.responseText
       *    
       *    `xml`: uses XHR.responseXML
       *    
       *    `json`: uses XHR.responseText parsed as JSON
       *  
       * @attribute handleAs
       * @type string
       * @default 'text'
       */
      handleAs: '',
      /**
       * If true, automatically performs an Ajax request when either url or params has changed.
       *
       * @attribute auto
       * @type boolean
       * @default false
       */
      auto: false,
      /**
       * Parameters to send to the specified URL, as JSON.
       *  
       * @attribute params
       * @type string (JSON)
       * @default ''
       */
      params: '',
      /**
       * Returns the response object.
       *
       * @attribute response
       * @type Object
       * @default null
       */
      ready: function() {
        this.xhr = document.createElement('polymer-xhr');
      },
      response: '',
      receive: function(response, xhr) {
        if (this.isSuccess(xhr)) {
          this.processResponse(xhr);
        } else {
          this.error(xhr);
        }
        this.complete(xhr);
      },
      isSuccess: function(xhr) {
        var status = xhr.status || 0;
        return !status || (status >= 200 && status < 300);
      },
      processResponse: function(xhr) {
        var response = this.evalResponse(xhr);
        this.response = response;
        this.fire('polymer-response', {response: response, xhr: xhr});
      },
      error: function(xhr) {
        var response = xhr.status + ': ' + xhr.responseText;
        this.fire('polymer-error', {response: response, xhr: xhr});
      },
      complete: function(xhr) {
        this.fire('polymer-complete', {response: xhr.status, xhr: xhr});
      },
      evalResponse: function(xhr) {
        return this[(this.handleAs || 'text') + 'Handler'](xhr);
      },
      xmlHandler: function(xhr) {
        return xhr.responseXML;
      },
      textHandler: function(xhr) {
        return xhr.responseText;
      },
      jsonHandler: function(xhr) {
        var r = xhr.responseText;
        try {
          return JSON.parse(r);
        } catch (x) {
          return r;
        }
      },
      urlChanged: function() {
        if (!this.handleAs) {
          var ext = String(this.url).split('.').pop();
          switch (ext) {
            case 'json':
              this.handleAs = 'json';
              break;
          }        
        }
        this.autoGo();
      },
      paramsChanged: function() {
        this.autoGo();
      },
      autoChanged: function() {
        this.autoGo();
      },
      // TODO(sorvell): multiple side-effects could call autoGo 
      // during one micro-task, use a job to have only one action 
      // occur
      autoGo: function() {
        if (this.auto) {
          this.goJob = this.job(this.goJob, this.go, 0);
        }
      },
      /**
       * Performs an Ajax request to the url specified.
       *
       * @method go
       */
      go: function() {
        var args = {};
        args.params = this.params || null;
        if (args.params && typeof(args.params) == 'string') {
          args.params = JSON.parse(args.params);
        }
        args.callback = this.receive.bind(this);
        args.url = this.url;
        return args.url && this.xhr.request(args);
      }
    });
  </script>
</polymer-element>
